<?php

App::uses('AppModel', 'Model');

class Location extends AppModel {
    
    const STATUS_FREE     = 0;
    const STATUS_RESERVED = 1;
    const STATUS_OCCUPIED = 2;
    
    public $name  = 'Location';
    public $order = 'Location.name';
    
    public $dateRange;
    
    public $validate = array (
        'name' => array (
            'rule'    => 'notEmpty',
            'message' => 'Morate uneti naziv lokacije'
        ),
        'address' => array (
            'rule'    => 'notEmpty',
            'message' => 'Morate uneti adresu lokacije'
        ),
        'width' => array (
            'required' => array (
                'rule'    => 'notEmpty',
                'message' => 'Morate uneti širinu prostora za reklamu na lokaciji'
            ),
            'isNumber' => array (
                'rule'    => 'numeric',
                'message' => 'Morate uneti broj za širinu prostora za reklamu na lokaciji. Drugi karakteri nisu dozvoljeni.'
            )
        ),
        'height' => array (
            'required' => array (
                'rule'    => 'notEmpty',
                'message' => 'Morate uneti visinu prostora za reklamu na lokaciji'
            ),
            'isNumber' => array (
                'rule'    => 'numeric',
                'message' => 'Morate uneti broj za visinu prostora za reklamu na lokaciji. Drugi karakteri nisu dozvoljeni.'
            )
        ),
        'rent_price' => array (
            'required' => array (
                'rule'    => 'notEmpty',
                'message' => 'Morate uneti visinu prostora za reklamu na lokaciji'
            ),
            'isNumber' => array (
                'rule'    => array ('decimal', 2, '/^\d+(\.\d+)?$/'),
                'message' => 'Morate uneti broj za visinu prostora za reklamu na lokaciji. Drugi karakteri nisu dozvoljeni.'
            )
        )
    );
    
    public $hasMany = array (
        'LocationImage' => array(
            'order'     => 'LocationImage.position',
            'dependent' => true
        ),
        'LocationReservation' => array(
            'order'     => 'LocationReservation.start DESC',
            'dependent' => true
        ),
        'LocationsAdType' => array( 'dependent' => true )
    );
    
    public $hasAndBelongsToMany = array(
        'AdType' => array( 'joinTable' => 'locations_ad_types' )
    );
    
    public function afterFind($results, $primary=false) {
        $results = parent::afterFind($results, $primary);
        
        if (! empty($results) && $primary) {
            
            foreach ($results as &$result) {
                if (empty($result['Location']) || !isset($result['LocationsAdType'])) {
                    continue;
                }
                                
                // CENA
                $price = $this->calculatePrice($result);
                $result['Location']['price'] = $price;
                $result['Location']['price_location'] = $this->calculatePriceArray($result);
                $result['Location']['price_formatted'] = number_format($price, 2, ",", ".");
                
                // STATUS
                $locId  = $result['Location']['id'];
                $status = $this->getStatus($locId);
                $status = $status[$locId];
                $result['Location']['status']        = $status['status'];
                $result['Location']['status_data'] = $status['data'];
            }
        }
        
        return $results;
    }

    public function deleteRelatedData() {
        if ($this->id) {
            $this->LocationsAdType->deleteAll(array('LocationsAdType.location_id' => $this->id));
        }
    }
    
    public function getStatus($locationIds) {

        if (! $this->Campaign) {
            App::import('Model', 'Campaign');
            $this->Campaign = new Campaign;
        }
        
        if (! $this->dateRange) {
            $this->dateRange = array(date('Y-m-d'), date('Y-m-d'));
        }

        if (! is_array($locationIds)) {
            $locationIds = array($locationIds);
        }

        $status = array_combine($locationIds, array_fill(0, count($locationIds), array(
            'status' => 'free',
            'data'   => null
        )));
        
        
        // verify if there's a Campaign for the given Location and dates
        $from = $this->dateRange[0];
        $to   = $this->dateRange[1];
        $sql = "
            SELECT 
                Campaign.id, Campaign.name,
                Location.id, Location.name,
		Client.id, Client.name
            FROM
                campaigns Campaign
                JOIN campaigns_locations cl ON Campaign.id=cl.campaign_id
                JOIN locations Location ON cl.location_id=Location.id
		JOIN clients Client ON Client.id=Campaign.client_id
            WHERE
                cl.location_id IN (". implode(", ", $locationIds) .") AND
                (
                    (cl.start BETWEEN '{$from}' AND '{$to}') OR
                    (cl.end BETWEEN '{$from}' AND '{$to}') OR
                    (cl.start < '{$from}' AND cl.end > '{$to}')
                )
        ";
        $data = $this->Campaign->query($sql);
        foreach ($data as $row) {
            $locId = $row['Location']['id'];
            $status[$locId]['status'] = 'occupied';
            $status[$locId]['data']   = $row;
        }
        
        // check if it's reserved
        $sql = "
            SELECT 
                LocationReservation.id, LocationReservation.start, LocationReservation.end, 
                Client.id, Client.name,
                Location.id, Location.name
            FROM 
                location_reservations LocationReservation
                JOIN locations Location ON LocationReservation.location_id = Location.id
                LEFT JOIN clients Client ON LocationReservation.client_id = Client.id
            WHERE 
                Location.id IN (". implode(", ", $locationIds).") AND 
                (
                    LocationReservation.start BETWEEN '{$from}' AND '{$to}' OR 
                    LocationReservation.end BETWEEN '{$from}' AND '{$to}' OR 
                    (LocationReservation.start < '{$from}' AND LocationReservation.end > '{$to}')
                )
        ";
        $reserved = $this->LocationReservation->query($sql);
        foreach ($reserved as $r) {
            $locId = $r['Location']['id'];
            if ($status[$locId]['status'] == 'free') {
                $status[$locId]['status'] = 'reserved';
                $status[$locId]['data']   = $r;
            }
        }

        return $status;
    }

    public function loadAdTypes($data) {
        $locationId = $data['Location']['id'];
        $locationAdTypes = $this->LocationsAdType->findAllByLocationId($locationId);
        foreach ($locationAdTypes as $k=>$locAdType) {
            $adType = $this->AdType->findById($locAdType['LocationsAdType']['ad_type_id']);
            
            $adType['AdType']['LocationsAdType'] = $locAdType['LocationsAdType'];
            $data['AdType'][$k] = $adType['AdType'];
        }
        
        return $data;
    }

    public function loadPrice($data) {
        $price = 0;
        
        if (empty($data['AdType']) && !empty($data['Location'])) {
            $data = $this->loadAdTypes($data);
        }
        
        $price = $this->calculatePrice($data);
        
        return $price;
    }

    public function calculatePrice($result) {
        $price = 0;
        foreach ($this->calculatePriceArray($result) as $p) {
            $price += $p;
        }
        return $price;
    }
    
    public function calculatePricePerLocation($adType) {
        $w = $adType['LocationsAdType']['width'];
        $h = $adType['LocationsAdType']['height'];
        $p = $adType['price'];
        $u = $adType['unit'];
        
        return $this->calculatePriceSingle($w, $h, $p, $u);
    }

    public function calculatePriceArray($result) {
        $prices = array();
        
        if (
            !empty($result['AdType']) && 
            is_array($result)
        ) {
            foreach ($result['AdType'] as $adType) {
                $prices[] = $this->calculatePricePerLocation($adType);
            }
        }
        
        return $prices;
    }

    public function calculatePriceSingle($width, $height, $priceByUnit, $unit) {
        $index = AdType::calculateIndex($unit, $width, $height);
        return $index * $priceByUnit;
    }
}
